#pragma once
#include "util.hpp"
#include "db.hpp"
#include "httplib.h"

namespace aod
{
#define WWWROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"
    TableVideo *tb_video = nullptr;
    class Server
    {
    public:
        Server(int port)
            : _port(port)
        {
        }
        bool RunModule()
        {
            //1. 初始化 tb_video指针
            tb_video = new TableVideo();
            //2. 创建三个目录：./wwwroot  ./www/video  ./www/image
            FileUtil(WWWROOT).createDirectory();
            std::string root = WWWROOT;
            std::string video_real_path = root+ VIDEO_ROOT; // ./www/video
            FileUtil(video_real_path).createDirectory();
            std::string image_real_path = root+ IMAGE_ROOT;
            FileUtil(image_real_path).createDirectory();
            //3. 搭建HTTP服务器
            _srv.set_mount_point("/",WWWROOT); //设置资源根目录
            _srv.Post("./video",Insert);
            _srv.Delete("./video/(\\d+)",Delete);
            _srv.Put("./video/(\\d+)",Update);
            _srv.Get("./video/(\\d+)",SelectOne);
            _srv.Get("./video",SelectALL);
            //启动服务器
            _srv.listen("0.0.0.0",_port);
            return true;
        }

    private:
        static void Insert(const httplib::Request &req, httplib::Response &res)
        {
            if (req.has_file("name") == false || req.has_file("info") == false || req.has_file("video") == false || req.has_file("image") == false)
            {
                res.status = 404;
                res.body = R"({"result":false,"reason":"上传的数据信息错误"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            httplib::MultipartFormData name = req.get_file_value("name");   // 视频名称
            httplib::MultipartFormData info = req.get_file_value("info");   // 视频简介
            httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
            httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件
            std::string video_name = name.content;
            std::string video_info = info.content;
            std::string root = WWWROOT;
            std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
            std::string image_path = root + IMAGE_ROOT + video_name + image.filename;

            if (FileUtil(video_path).setContent(video.content) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"视频文件存储失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            if (FileUtil(image_path).setContent(image.content) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"图片文件存储失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            // 视频和图片文件正确存储，需将视频相关元信息写入数据库
            Json::Value video_json;
            video_json["name"] = video_name;
            video_json["info"] = video_info;
            video_json["video"] = VIDEO_ROOT + video_name + video.filename;
            video_json["image"] = IMAGE_ROOT + video_name + image.filename;
            if (tb_video->insert(video_json) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"数据库新增数据失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            res.set_redirect("/index.html", 303);
        }
        static void Delete(const httplib::Request &req, httplib::Response &res)
        {
            // 1. 获取要删除的视频ID
            // 2. 删除视频以及图片信息
            // 3. 删除数据库信息
            int video_id = std::stoi(req.matches[1]);
            Json::Value video;
            // 先判断要删除的视频文件是否存在
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"不存在该视频信息"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            // 若存在：
            std::string root = WWWROOT;
            std::string video_path = root + video["video"].asString();
            std::string image_path = root + video["image"].asString();
            remove(video_path.c_str());
            remove(image_path.c_str());
            // 删除数据库存储的该视频相关信息
            if (tb_video->Delete(video_id) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"删除数据库信息失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
        }
        static void Update(const httplib::Request &req, httplib::Response &res)
        {
            int video_id = std::stoi(req.matches[1]);
            Json::Value video;
            // 先判断要修改的视频文件是否存在
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"不存在该视频信息"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            // 若存在，则修改

            //Json::Value video;
            if (JsonUtil::unSerialize(req.body, &video) == false)
            {
                res.status = 400;
                res.body = R"({"result":false,"reason":"更改的视频相关信息解析失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            if (tb_video->update(video_id, video) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"修改数据库相关信息失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
        }
        static void SelectOne(const httplib::Request &req, httplib::Response &res)
        {
            int video_id = std::stoi(req.matches[1]);
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                res.status = 500;
                res.body = R"({"result":false,"reason":"获取某视频相关信息失败"})";
                res.set_header("Content-Type", "application/json");
                return;
            }
            // 序列化：
            JsonUtil::serialize(video, &res.body);
            res.set_header("Content-Type", "application/json");
        }
        static void SelectALL(const httplib::Request &req, httplib::Response &res)
        {
            bool select_flag = true;
            std::string search_key;
            if (req.has_param("search") == true)
            {
                select_flag = false;
                search_key = req.get_param_value("search");
            }
            Json::Value videos;
            if (select_flag == true)
            {
                if (tb_video->SelectAll(&videos) == false)
                {
                    res.status = 500;
                    res.body = R"({"result":false,"reason":"获取所有的视频信息失败"})";
                    res.set_header("Content-Type", "application/json");
                    return;
                }
            }
            else
            {
                if (tb_video->SelectLike(search_key,&videos) == false)
                {
                    res.status = 500;
                    res.body = R"({"result":false,"reason":"模糊获取视频信息失败"})";
                    res.set_header("Content-Type", "application/json");
                    return;
                }
            }
            // 成功查询
            JsonUtil::serialize(videos, &res.body);
            res.set_header("Content-Type", "application/json");
        }

    private:
        int _port;
        httplib::Server _srv;
    };
}